package com.mspbots.rule.exceptions.tsheet;

import cn.hutool.core.util.StrUtil;
import com.mspbots.cw.request.AttendanceDTO;
import com.mspbots.cw.request.SheetsTimeDTO;
import lombok.extern.slf4j.Slf4j;
import org.jeasy.rules.annotation.Action;
import org.jeasy.rules.annotation.Condition;
import org.jeasy.rules.annotation.Fact;
import org.jeasy.rules.annotation.Rule;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.StringUtils;

import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;

import static java.time.temporal.ChronoUnit.SECONDS;

/**
 * com.mspbots.rule.exceptions.tsheet.BODtsheetCheck
 *
 * @author Jun Zhou
 * @date 16:11 2019/7/30
 **/
@Slf4j
@Rule(name = "TsheetInCheck", description = "TsheetInCheck")
public class TsheetInCheck extends TSheetBaseRule {

    protected StringRedisTemplate stringRedisTemplate;
    private boolean AUTO_IN = false;
    private LocalDateTime logTime;
    private AttendanceDTO attendanceDTO;

    @Condition
    public boolean condition(@Fact(FACT) SheetsTimeDTO tSheetsTimeDTO) {
        try {
            if (setTenantUserMapping(tSheetsTimeDTO.getTsUid(), tSheetsTimeDTO.getTenantId())) {
                if (checkDayMessage(tenantUserMappingDTO.getTenantUserId())) {
                    return false;
                }
                if (StringUtils.isEmpty(tenantUserMappingDTO.getTeamsUserId())) {
                    log.info("TsheetInCheck teamsUserId is null {}", tSheetsTimeDTO.getId());
                    return false;
                }
                Map<String, Object> attendanceParams = Map.of("tenantId", tenantUserMappingDTO.getTenantId(),
                        "userId", tenantUserMappingDTO.getTenantUserId(), "type", "IN");
                attendanceDTO = this.coreClient.get("/attendances/last", attendanceParams, AttendanceDTO.class).block(Duration.of(5, SECONDS));
                log.info("tsheet attendance : {}", attendanceDTO);
                // if there is no BOD,
                if (attendanceDTO == null || !BODin12Hour(attendanceDTO)) {
                    AUTO_IN = true;
                }
                logTime = tSheetsTimeDTO.getStartTime();
                return true;
            } else {
                log.error("tsheet user [{}] has no mapping...", tSheetsTimeDTO.getSheetUserId());
                return false;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Action
    public void action(@Fact(FACT) SheetsTimeDTO tSheetsTimeDTO) {
        Map<String, Object> params = Map.of("tenantId", tSheetsTimeDTO.getTenantId(), "sheetUserId", tSheetsTimeDTO.getSheetUserId(),
                "startTimeFrom", LocalDateTime.of(tSheetsTimeDTO.getStartTime().plusHours(
                        Integer.parseInt(tenantUserMappingDTO.getTz().substring(0, 3))).toLocalDate(), LocalTime.MIN).plusHours(Integer.parseInt(tenantUserMappingDTO.getTz().substring(0, 3))),
                "startTimeTo", LocalDateTime.of(tSheetsTimeDTO.getStartTime().plusHours(
                        Integer.parseInt(tenantUserMappingDTO.getTz().substring(0, 3))).toLocalDate(), LocalTime.MAX).plusHours(Integer.parseInt(tenantUserMappingDTO.getTz().substring(0, 3))));
        SheetsTimeDTO sheetsTimeDTO = this.coreClient.get("/sheet-times/last", params, SheetsTimeDTO.class).block();
        if (!StringUtils.isEmpty(sheetsTimeDTO)) {
            messages.setMessage(formatMessage(sheetsTimeDTO.getStartTime()) + suffixMessage(tSheetsTimeDTO.getSheetId(), sheetsTimeDTO.getStartTime()));
        } else {
            messages.setMessage(formatMessage(tSheetsTimeDTO.getStartTime()) + suffixMessage(tSheetsTimeDTO.getSheetId(), tSheetsTimeDTO.getStartTime()));
        }
        messages.setTsheetTimesId(tSheetsTimeDTO.getSheetId());
        messages.setBusinessId(tSheetsTimeDTO.getSheetId());
        insertMessage();
        if (!StringUtils.isEmpty(sheetsTimeDTO)) {
            log.info("tsheetTimeDTO_{}", tSheetsTimeDTO);
            if (AUTO_IN) {
                Map<String, String> attendanceParams = Map.of("teamsUserId", tenantUserMappingDTO.getTeamsUserId(),
                        "logTime", DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(
                                sheetsTimeDTO.getStartTime().plusHours(
                                        Integer.parseInt(tenantUserMappingDTO.getTz().substring(0, 3)))),
                        "fromType", "1");
                this.coreClient.post("/teams/user-message/in", attendanceParams).subscribe();
            } else {
                Map<String, Object> attendanceParams = Map.of(
                        "id", attendanceDTO.getId(),
                        "tenantId", tenantUserMappingDTO.getTenantId(),
                        "logTime", DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(
                                sheetsTimeDTO.getStartTime().plusHours(
                                        Integer.parseInt(tenantUserMappingDTO.getTz().substring(0, 3)))),
                        "userId", tenantUserMappingDTO.getTenantUserId(),
                        "teamsId", tenantUserMappingDTO.getTeamsUserId(),
                        "tz", tenantUserMappingDTO.getTz(),
                        "tzStr", tenantUserMappingDTO.getTzStr(),
                        "fromType", "1");
                this.coreClient.post("/attendances/save", attendanceParams).subscribe();
            }
        } else {
            log.info("tsheetTimeDTO_{}", tSheetsTimeDTO);
            if (AUTO_IN) {
                Map<String, String> attendanceParams = Map.of("teamsUserId", tenantUserMappingDTO.getTeamsUserId(),
                        "logTime", DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(
                                tSheetsTimeDTO.getStartTime().plusHours(
                                        Integer.parseInt(tenantUserMappingDTO.getTz().substring(0, 3)))),
                        "fromType", "1");
                this.coreClient.post("/teams/user-message/in", attendanceParams).subscribe();
            } else {
                Map<String, Object> attendanceParams = Map.of(
                        "id", attendanceDTO.getId(),
                        "tenantId", tenantUserMappingDTO.getTenantId(),
                        "logTime", DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(
                                tSheetsTimeDTO.getStartTime().plusHours(
                                        Integer.parseInt(tenantUserMappingDTO.getTz().substring(0, 3)))),
                        "userId", tenantUserMappingDTO.getTenantUserId(),
                        "teamsId", tenantUserMappingDTO.getTeamsUserId(),
                        "tz", tenantUserMappingDTO.getTz(),
                        "tzStr", tenantUserMappingDTO.getTzStr(),
                        "fromType", "1");
                this.coreClient.post("/attendances/save", attendanceParams).subscribe();
            }
        }
    }

    protected String formatMessage(LocalDateTime lastModified) {
        StringBuilder message = new StringBuilder();
        String tenantTemp = StringUtils.isEmpty(this.tenantRuleDTO.getTemplate()) ?
                this.tenantRuleDTO.getSysTemplate() : this.tenantRuleDTO.getTemplate();
        String template = AUTO_IN ? tenantTemp.split("\\|")[1]
                : tenantTemp.split("\\|")[0];
        String checkInTime = "";

        checkInTime = lastModified.plusHours(Integer.parseInt(tenantUserMappingDTO.getTz().substring(0, 3))).format(DateTimeFormatter.ofPattern("MM/dd HH:mm")) + " " + tenantUserMappingDTO.getTzStr();

        this.params = Map.of("USER", StringUtils.isEmpty(tenantUserMappingDTO.getFirstName()) ? tenantUserMappingDTO.getUserName() : tenantUserMappingDTO.getFirstName(),
                "CheckinTime", styleParam(checkInTime));

        message.append(StrUtil.format(template, this.params)).append("<br>").append(suffixEscalation());
        return message.toString();
    }


    @Override
    protected StringBuilder suffixMessage(Long sheetId, LocalDateTime lastModified) {
        LocalDateTime logTimeStr = lastModified.plusHours(Integer.parseInt(tenantUserMappingDTO.getTz().substring(0, 3)));
        return new StringBuilder().append("--<span style='color:#999d9c;font-size:10px;'>")
                .append(suffixUserName())
//                .append(suffixSheetLink(sheetId))
                .append(suffixZoneTime(logTimeStr))
                .append("</span>");

    }

    protected StringBuilder suffixZoneTime(LocalDateTime enteredDateTime) {
        return new StringBuilder().append("[")
                .append(enteredDateTime.format(DateTimeFormatter.ofPattern("MM/dd/yy HH:mm")))
                .append("/")
                .append(tenantUserMappingDTO.getTzStr())
                .append("]");

    }

    protected boolean BODin12Hour(AttendanceDTO attendanceDTO) {
        Integer tz = Integer.parseInt(attendanceDTO.getTz().substring(0, 3));
        log.info("tz parse :{}    {}", attendanceDTO.getTz(), tz);
        return LocalDateTime.now().minusHours(12).isBefore(attendanceDTO.getLogTime().minusHours(tz));
    }


}
